/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.editor.java;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Enumeration;
import javax.swing.event.DocumentEvent;
import javax.swing.text.Document;
import javax.swing.text.BadLocationException;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.JumpList;
import org.netbeans.editor.ext.JavaSyntaxSupport;
import org.netbeans.editor.ext.JCClass;
import org.netbeans.editor.ext.JCType;
import org.netbeans.editor.ext.JCompletion;
import org.netbeans.editor.ext.JCFinder;
import org.netbeans.editor.ext.JCField;
import org.netbeans.editor.ext.JCParameter;
import org.netbeans.editor.ext.JCUtilities;
import org.netbeans.editor.ext.JCPackage;
import org.netbeans.editor.ext.JCMethod;
import org.netbeans.editor.ext.JCConstructor;
import org.netbeans.editor.ext.JCView;
import org.netbeans.editor.ext.JCQuery;
import org.netbeans.modules.editor.KitSupport;
import org.openide.TopManager;
import org.openide.src.SourceElement;
import org.openide.src.ClassElement;
import org.openide.src.Identifier;
import org.openide.src.FieldElement;
import org.openide.src.Element;
import org.openide.src.MemberElement;
import org.openide.src.InitializerElement;
import org.openide.src.MethodElement;
import org.openide.src.ConstructorElement;
import org.openide.src.Type;
import org.openide.cookies.SourceCookie;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.OpenCookie;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.Repository;
import org.openide.filesystems.FileSystemCapability;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.nodes.Node;
import org.openide.debugger.Debugger;
import org.openide.debugger.DebuggerNotFoundException;
import org.openide.debugger.Breakpoint;
import org.openide.text.Line;
/**
* Support methods for syntax analyzes
*
* @author Miloslav Metelka
* @version 1.00
*/
public class NbJavaSyntaxSupport extends JavaSyntaxSupport {
private static final String PACKAGE_SUMMARY = "package-summary"; // NOI18N
private HashMap jcLookupCache = new HashMap(307);
private boolean jcValid;
public NbJavaSyntaxSupport(BaseDocument doc) {
super(doc);
}
protected void documentModified(DocumentEvent evt) {
super.documentModified(evt);
jcValid = false;
}
protected int getMethodStartPosition(int pos) {
DataObject dob = KitSupport.getDataObject(doc);
if (dob != null) {
try {
SourceCookie.Editor sce = (SourceCookie.Editor)dob.getCookie(SourceCookie.Editor.class);
if (sce != null) {
Element elem = sce.findElement(pos);
if (elem != null) {
javax.swing.text.Element swingElem = sce.sourceToText(elem);
if (swingElem != null) {
return swingElem.getStartOffset();
}
}
}
} catch (NullPointerException e) { // due to some bug in parser !!! [PENDING]
}
}
return 0;
}
public int findGlobalDeclarationPosition(String varName, int varPos) {
Element e = getElementAtPos(varPos);
if (e instanceof MemberElement) {
MemberElement me = (MemberElement)e;
while (me != null) {
if (me instanceof ClassElement) {
ClassElement ce = (ClassElement)me;
FieldElement[] fields = ce.getFields();
if (fields != null) {
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().getFullName().equals(varName)) {
DataObject dob = KitSupport.getDataObject(doc);
if (dob != null) {
SourceCookie.Editor sce = (SourceCookie.Editor)dob.getCookie(SourceCookie.Editor.class);
if (sce != null) {
javax.swing.text.Element elem = sce.sourceToText(fields[i]);
if (elem != null) {
return elem.getStartOffset();
}
}
}
}
}
}
}
me = me.getDeclaringClass();
}
}
return -1;
}
private Element getElementAtPos(int pos) {
DataObject dob = KitSupport.getDataObject(doc);
if (dob != null) {
SourceCookie.Editor sce = (SourceCookie.Editor)dob.getCookie(SourceCookie.Editor.class);
if (sce != null) {
return sce.findElement(pos);
}
}
return null;
}
/** Get the class element(s) according to the current position */
private ClassElement getClassElement(int pos) {
ClassElement ce = null;
Element elem = getElementAtPos(pos);
if (elem instanceof ClassElement) {
ce = (ClassElement)elem;
} else if (elem instanceof MemberElement) {
ce = ((MemberElement)elem).getDeclaringClass();
} else if (elem instanceof InitializerElement) {
ce = ((InitializerElement)elem).getDeclaringClass();
}
return ce;
}
public JCClass getClass(int pos) {
ClassElement ce = getClassElement(pos);
if (ce != null) {
return JCompletion.getFinder().getExactClass(ce.getName().getFullName());
}
return null;
}
public boolean isStaticBlock(int pos) {
Element elem = getElementAtPos(pos);
if (elem instanceof MethodElement) {
return (((MethodElement)elem).getModifiers() & Modifier.STATIC) != 0;
} else if (elem instanceof FieldElement) {
return (((FieldElement)elem).getModifiers() & Modifier.STATIC) != 0;
} else if (elem instanceof InitializerElement) {
return true;
}
return false;
}
private ClassElement[] getAllClassElements() {
DataObject dob = KitSupport.getDataObject(doc);
if (dob != null) {
SourceCookie sc = (SourceCookie)dob.getCookie(SourceCookie.class);
if (sc != null) {
SourceElement se = sc.getSource();
if (se != null) {
return se.getAllClasses();
}
}
}
return null;
}
public void refreshCompletion() {
if (!jcValid) {
JCFinder finder = JCompletion.getFinder();
ClassElement[] ces = getAllClassElements(); // all class elements from the document
if (ces != null) {
for (int i = 0; i < ces.length; i++) {
JCClass classToAppend = JCExtension.parseClassElement(ces[i], JCompletion.PRIVATE_LEVEL,
JCompletion.PRIVATE_LEVEL, JCompletion.PRIVATE_LEVEL, jcLookupCache, true);
if (classToAppend != null) {
finder.append(new JCompletion.SingleProvider(classToAppend));
// refreshParents(classToAppend); !!! takes too much time
}
}
}
jcValid = true;
}
}
private void refreshParents(JCClass cls) {
JCFinder finder = JCompletion.getFinder();
ArrayList clsList = new ArrayList();
clsList.add(cls);
while (true) {
cls = cls.getSuperclass();
if (cls == null || cls.equals(JCompletion.INVALID_CLASS) || clsList.indexOf(cls) >= 0) {
break;
}
JCClass fc = finder.getExactClass(cls.getFullName());
if (fc == null) {
ClassElement ce = ClassElement.forName(cls.getFullName());
if (ce != null) {
fc = JCExtension.parseClassElement(ce, JCompletion.PRIVATE_LEVEL,
JCompletion.PRIVATE_LEVEL, JCompletion.PRIVATE_LEVEL, jcLookupCache, true);
}
if (fc == null) {
break; // break the whole loop if not found
}
finder.append(new JCompletion.SingleProvider(fc));
}
cls = fc;
clsList.add(cls);
}
}
protected Map buildGlobalVariableMap(int pos) {
refreshCompletion();
JCFinder finder = JCompletion.getFinder();
JCClass cls = getClass(pos);
if (cls != null) {
HashMap varMap = new HashMap();
List fldList = finder.findFields(cls, "", false, false, true); // NOI18N
for (int i = fldList.size() - 1; i >= 0; i--) {
JCField fld = (JCField)fldList.get(i);
varMap.put(fld.getName(), fld.getType());
}
return varMap;
}
return null;
}
private ClassElement recurseClasses(ClassElement[] classes, String name) {
for (int i = 0; i < classes.length; i++) {
ClassElement ce = classes[i];
if (ce.getName().getFullName().replace('$', '.').equals(name)) {
return ce;
}
ClassElement inner = recurseClasses(ce.getClasses(), name);
if (inner != null) {
return inner;
}
}
return null;
}
private DataObject getDataObject(FileObject fo) {
DataObject dob = null;
if (fo != null) {
try {
dob = DataObject.find(fo);
} catch (DataObjectNotFoundException e) {
}
}
return dob;
}
private DataObject getDataObject(Repository rep, JCClass cls) {
DataObject dob = null;
String clsName = cls.getName();
int dotInd = clsName.indexOf('.', 0);
if (dotInd >= 0) {
clsName = clsName.substring(0, dotInd);
}
FileObject fo = rep.find(cls.getPackageName(), clsName, "java"); // NOI18N
if (fo != null) {
dob = getDataObject(fo);
}
return dob;
}
private SourceElement getSourceElement(DataObject classDOB) {
SourceElement se = null;
if (classDOB != null) {
SourceCookie sc = (SourceCookie)classDOB.getCookie(SourceCookie.class);
if (sc != null) {
se = sc.getSource();
}
}
return se;
}
private ClassElement getClassElement(DataObject classDOB, JCClass cls) {
SourceElement se = getSourceElement(classDOB);
ClassElement ce = null;
if (se != null) {
ce = recurseClasses(se.getClasses(), cls.getFullName());
}
return ce;
}
private void openAtElement(final DataObject classDOB, final Element e) {
new Thread() {
public void run() {
OpenCookie oc = (e != null)
? (OpenCookie)e.getCookie(OpenCookie.class)
: (OpenCookie)classDOB.getCookie(OpenCookie.class);
if (oc != null) {
oc.open();
return;
}
}
}.start();
}
private String getSourceName(JCClass cls, boolean shortName) {
String name = cls.getName();
int icInd = name.indexOf('.');
if (icInd >= 0) { // inner class name
name = name.substring(0, icInd);
}
return shortName ? name : cls.getPackageName() + '.' + name;
}
/** Open the source according to the given object.
* @param item completion object that is decoded and the appropriate
* source is opened.
* @param findDeclaration find the declaration behaior that is different
* for the fields - it opens the source of the type of the field.
* @param simulate simulate the opening but don't open in reality.
* @return for simulate mode return the short display name (without package name)
* of the item or null if the item is not recognized.
* For non-simulate mode return the null if the item was successfully opened
* or the display name if the item's object can't be found.
*/
public String openSource(Object item, boolean findDeclaration, boolean simulate) {
TopManager tm = TopManager.getDefault();
Repository rep = tm.getRepository();
DataObject dob = null;
Element elem = null;
String ret = null;
boolean found = false;
if (item instanceof JCPackage) {
if (!findDeclaration) {
String pkgName = ((JCPackage)item).getName();
FileObject fo = rep.find(pkgName, null, null);
if (fo != null) {
dob = getDataObject(fo);
if (dob != null) {
Node node = dob.getNodeDelegate();
if (node != null) {
found = true;
if (!simulate) {
tm.getNodeOperation().explore(node); // explore the package
}
}
dob = null; // don't try to open dob
}
}
if (simulate || !found) {
ret = pkgName;
}
}
} else if (item instanceof JCClass) {
JCClass cls = (JCClass)item;
if (!JCompletion.isPrimitiveClass(cls)) {
dob = getDataObject(rep, cls);
if (dob != null) {
found = true;
elem = getClassElement(dob, cls);
}
if (simulate || !found) {
ret = getSourceName(cls, simulate);
}
}
} else if (item instanceof JCField) {
JCField fld = (JCField)item;
JCClass cls = findDeclaration ? fld.getClazz() : fld.getType().getClazz();
if (!JCompletion.isPrimitiveClass(cls)) {
dob = getDataObject(rep, cls);
if (dob != null) {
found = true;
ClassElement ce = getClassElement(dob, cls);
if (ce != null) {
elem = JCExtension.findFieldElement(fld, ce);
}
}
if (simulate || !found) {
ret = getSourceName(cls, simulate);
}
}
} else if (item instanceof JCMethod) {
JCMethod mtd = (JCMethod)item;
JCClass cls = mtd.getClazz();
if (!JCompletion.isPrimitiveClass(cls)) {
dob = getDataObject(rep, cls);
if (dob != null) {
found = true;
ClassElement ce = getClassElement(dob, cls);
if (ce != null) {
elem = JCExtension.findMethodElement(mtd, ce);
}
}
if (simulate || !found) {
ret = getSourceName(cls, simulate);
}
}
} else if (item instanceof JCConstructor) {
JCConstructor ctr = (JCConstructor)item;
JCClass cls = ctr.getClazz();
if (!JCompletion.isPrimitiveClass(cls)) {
dob = getDataObject(rep, cls);
if (dob != null) {
found = true;
ClassElement ce = getClassElement(dob, cls);
if (ce != null) {
elem = JCExtension.findConstructorElement(ctr, ce);
}
}
if (simulate || !found) {
ret = getSourceName(cls, simulate);
}
}
}
// Add the current (probably opened) componetn to jump-list
if (dob != null) {
if (!simulate) {
openAtElement(dob, elem);
KitSupport.addJumpListEntry(dob);
}
}
return ret;
}
private FileSystem[] getDocFileSystems() {
Enumeration en = TopManager.getDefault().getRepository().getFileSystems();
ArrayList fsList = new ArrayList();
while (en.hasMoreElements()) {
FileSystem fs = (FileSystem)en.nextElement();
if (fs.getCapability().capableOf(FileSystemCapability.DOC)) {
fsList.add(fs);
}
}
FileSystem[] ret = new FileSystem[fsList.size()];
fsList.toArray(ret);
return ret;
}
private FileObject[] getDocFileObjects(String pkg, String name) {
FileSystem[] fss = getDocFileSystems();
ArrayList foList = new ArrayList();
String apiPkg = "api." + pkg; // NOI18N
for (int i = 0; i < fss.length; i++) {
FileObject fo = fss[i].find(pkg, name, "html"); // NOI18N
if (fo == null) {
fo = fss[i].find(apiPkg, name, "html"); // NOI18N
}
if (fo != null) {
foList.add(fo);
}
}
FileObject[] ret = new FileObject[foList.size()];
foList.toArray(ret);
return ret;
}
public URL[] getJavaDocURLs(Object obj) {
ArrayList urlList = new ArrayList();
if (obj instanceof JCPackage) {
JCPackage pkg = (JCPackage)obj;
FileObject[] fos = getDocFileObjects(pkg.getName(), PACKAGE_SUMMARY);
for (int i = 0; i < fos.length; i++) {
try {
urlList.add(fos[i].getURL());
} catch (FileStateInvalidException e) {
}
}
} else if (obj instanceof JCClass) {
JCClass cls = (JCClass)obj;
FileObject[] fos = getDocFileObjects(cls.getPackageName(), cls.getName());
for (int i = 0; i < fos.length; i++) {
try {
urlList.add(fos[i].getURL());
} catch (FileStateInvalidException e) {
}
}
} else if (obj instanceof JCConstructor) { // covers JCMethod too
JCConstructor ctr = (JCConstructor)obj;
JCClass cls = ctr.getClazz();
FileObject[] fos = getDocFileObjects(cls.getPackageName(), cls.getName());
for (int i = 0; i < fos.length; i++) {
try {
URL url = fos[i].getURL();
StringBuffer sb = new StringBuffer("#"); // NOI18N
sb.append((obj instanceof JCMethod) ? ((JCMethod)ctr).getName() : cls.getName());
sb.append('(');
JCParameter[] parms = ctr.getParameters();
int cntM1 = parms.length - 1;
for (int j = 0; j <= cntM1; j++) {
sb.append(parms[j].getType().format(true));
if (j < cntM1) {
sb.append(", "); // NOI18N
}
}
sb.append(')');
try {
urlList.add(new URL(url.toString() + sb));
} catch (MalformedURLException e) {
}
} catch (FileStateInvalidException e) {
}
}
} else if (obj instanceof JCField) {
JCField fld = (JCField)obj;
JCClass cls = fld.getClazz();
FileObject[] fos = getDocFileObjects(cls.getPackageName(), cls.getName());
for (int i = 0; i < fos.length; i++) {
try {
URL url = fos[i].getURL();
try {
urlList.add(new URL(url.toString() + '#' + fld.getName()));
} catch (MalformedURLException e) {
}
} catch (FileStateInvalidException e) {
}
}
}
URL[] ret = new URL[urlList.size()];
urlList.toArray(ret);
return ret;
}
public Debugger getDebugger() {
try {
return TopManager.getDefault().getDebugger();
} catch (DebuggerNotFoundException e) {
return null;
}
}
public Breakpoint getBreakpoint(int pos) {
Debugger debugger = getDebugger();
Line line = KitSupport.getLine(doc, pos);
if (debugger != null && line != null) {
return debugger.findBreakpoint(line);
}
return null;
}
public Breakpoint createBreakpoint(int pos) {
Debugger debugger = getDebugger();
Line line = KitSupport.getLine(doc, pos);
if (debugger != null && line != null) {
return debugger.createBreakpoint(line);
}
return null;
}
}
/*
* Log
* 19 Gandalf 1.18 1/26/00 Miloslav Metelka refreshParents() not
* called
* 18 Gandalf 1.17 1/18/00 Miloslav Metelka
* 17 Gandalf 1.16 1/13/00 Miloslav Metelka Localization
* 16 Gandalf 1.15 1/11/00 Miloslav Metelka
* 15 Gandalf 1.14 1/10/00 Miloslav Metelka
* 14 Gandalf 1.13 1/7/00 Miloslav Metelka
* 13 Gandalf 1.12 1/4/00 Miloslav Metelka
* 12 Gandalf 1.11 12/28/99 Miloslav Metelka
* 11 Gandalf 1.10 11/14/99 Miloslav Metelka
* 10 Gandalf 1.9 11/11/99 Miloslav Metelka
* 9 Gandalf 1.8 11/9/99 Miloslav Metelka
* 8 Gandalf 1.7 11/8/99 Miloslav Metelka
* 7 Gandalf 1.6 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 6 Gandalf 1.5 10/10/99 Miloslav Metelka
* 5 Gandalf 1.4 9/15/99 Miloslav Metelka
* 4 Gandalf 1.3 9/10/99 Miloslav Metelka
* 3 Gandalf 1.2 8/18/99 Miloslav Metelka
* 2 Gandalf 1.1 8/18/99 Miloslav Metelka
* 1 Gandalf 1.0 7/30/99 Miloslav Metelka
* $
*/